﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using UBCon.Ribbon.Interfaces;

namespace UBCon.Ribbon
{
    /// <summary>
    /// Represents custom panel for RibbonGallery control.
    /// </summary>
    internal class RibbonGalleryPanel:Panel, IRibbonControl
    {
        #region Constructors
        #endregion

        #region Properties

        /// <summary>
        /// Identifies current start index.
        /// </summary>
        internal int CurrentIndex
        {
            get { return (int)GetValue(CurrentIndexProperty); }
            set { SetValue(CurrentIndexProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurrentIndex.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty CurrentIndexProperty =
            DependencyProperty.Register("CurrentIndex", typeof(int), typeof(RibbonGalleryPanel),
            new FrameworkPropertyMetadata(-1, FrameworkPropertyMetadataOptions.AffectsMeasure));

        /// <summary>
        /// Gets or sets maximum measurable items count.
        /// This is a dependency property.
        /// </summary>
        internal int VisibleItemsCount
        {
            get { return (int)GetValue(VisibleItemsCountProperty); }
            set { SetValue(VisibleItemsCountProperty, value); }
        }

        // Using a DependencyProperty as the backing store for VisibleItemsCount.  This enables animation, styling, binding, etc...
        internal static readonly DependencyProperty VisibleItemsCountProperty =
            DependencyProperty.Register("VisibleItemsCount", typeof(int), typeof(RibbonGalleryPanel),
            new FrameworkPropertyMetadata(3,
                FrameworkPropertyMetadataOptions.Journal | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));



        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(RibbonGallery), 
            new FrameworkPropertyMetadata(Orientation.Horizontal));

        
        #endregion

        #region Depenency Property Changed Callbacks
        
        #endregion

        #region Overrides

        /// <summary>
        /// Invalidates the arrange state (layout) for the element. 
        /// After the invalidation, the element will have its layout updated, which will occur 
        /// asynchronously unless subsequently forced by UpdateLayout. (Inherited from UIElement.)
        /// </summary>
        /// <param name="finalSize">The finalSize size that this element can give to child elements. 
        /// Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
        /// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            x = 0;
            y = 0;

            if (CurrentIndex >= 0)
            {
                UIElement elt = null;

                int threshold = Math.Min((CurrentIndex + 1) * VisibleItemsCount, InternalChildren.Count);

                for (int i = 0; i < InternalChildren.Count; i++)
                {
                    elt = InternalChildren[i];

                    if (i >= CurrentIndex * VisibleItemsCount && i < threshold)
                    {
                        elt.Visibility = System.Windows.Visibility.Visible;

                        arrangeRect.X = x;
                        arrangeRect.Y = 0;
                        arrangeRect.Width = elt.DesiredSize.Width;
                        arrangeRect.Height = elt.DesiredSize.Height;

                        elt.Arrange(arrangeRect);

                        x += elt.DesiredSize.Width;
                        y = Math.Max(elt.DesiredSize.Height, y);
                    }
                    else
                    {
                        elt.Visibility = System.Windows.Visibility.Collapsed;
                    }
                }
            }
            else 
            {
                UIElement elt = null;

                for (int i = 0; i < InternalChildren.Count; i++)
                {
                    elt = InternalChildren[i];
                    elt.Visibility = System.Windows.Visibility.Collapsed;
                }
            }

            if (!double.IsPositiveInfinity(finalSize.Width))
            {
                InitialSize.Width = Math.Max(finalSize.Width, InitialSize.Width);
            }

            InitialSize.Width = Math.Max(InitialSize.Width, x);

            measureSize.Width = InitialSize.Width;

            if (!double.IsPositiveInfinity(finalSize.Height))
            {
                InitialSize.Height = Math.Max(finalSize.Height, InitialSize.Height);
            }

            InitialSize.Height = Math.Max(InitialSize.Height, x);

            measureSize.Height = InitialSize.Height;

            return measureSize;
        }

        /// <summary>
        /// Invalidates the measurement state (layout) for the element. (Inherited from UIElement.)
        /// </summary>
        /// <param name="availableSize">The available size that this element can give to child elements. 
        /// Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
        /// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            x = 0; 
            y = 0;
            if (CurrentIndex >= 0)
            {
                UIElement elt = null;

                int threshold = Math.Min((CurrentIndex + 1) * VisibleItemsCount, InternalChildren.Count);

                for (int i = 0; i < InternalChildren.Count; i++)
                {
                    elt = InternalChildren[i];

                    if (i >= CurrentIndex * VisibleItemsCount && i < threshold)
                    {
                        elt.Visibility = System.Windows.Visibility.Visible;

                        elt.Measure(infiniteSize);
                        x += elt.DesiredSize.Width;
                        y = Math.Max(elt.DesiredSize.Height, y);
                    }
                    //else 
                    //{
                    //    elt.Visibility = System.Windows.Visibility.Collapsed;
                    //}
                }
            }
            
            if (!double.IsPositiveInfinity(availableSize.Width))
            {
                InitialSize.Width = Math.Max(availableSize.Width, InitialSize.Width);
            }

            InitialSize.Width = Math.Max(InitialSize.Width, x);

            measureSize.Width = InitialSize.Width;

            if (!double.IsPositiveInfinity(availableSize.Height))
            {
                InitialSize.Height = Math.Max(availableSize.Height, InitialSize.Height);
            }

            InitialSize.Height = Math.Max(InitialSize.Height, x);

            measureSize.Height = InitialSize.Height;

            return measureSize;
        }
        #endregion

        #region public Methods
        #endregion

        #region Internal Methods
        #endregion

        #region Private Methods

        /// <summary>
        /// Updates an interval according to specified selected index.
        /// </summary>
        /// <param name="index">Type: System.Int32. Current SelectedIndex.</param>
        private void UpdateInterval(int index)
        {
            StartIndex = startIndexes[index];

            EndIndex = endIndexes[index];

        }

        #endregion

        #region Event Handlers
        #endregion

        #region Fields

        private int StartIndex = 0, EndIndex = 0;

        private List<int> startIndexes = new List<int>();

        private List<int> endIndexes = new List<int>();

        private Size measureSize = new Size(0, 0);

        private Size infiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);

        private Rect arrangeRect = new Rect();

        private Size InitialSize = new Size();

        private Size emtpySize = new Size(0,0);
        private double x = 0, y = 0;

        #endregion

        #region Events
        #endregion

        #region Commands
        #endregion

        #region IRibbonControl Implementation

        /// <summary>
        /// Gets a boolean value indicating whether the contol's size is large
        /// </summary>
        public bool IsLarge
        {
            get { return true; }
        }

        #endregion

    }
}
